<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 定义函数
    // function foo(name) {
    //   console.log("foo函数:", this)
    // }

    // 1.方式一: 直接调用  => this指向window
    // foo()

    // 2.方式二: 通过对象调起  => this指向obj
    // var obj = { name: "张三" }
    // obj.aaa = foo
    // obj.aaa()
    // this指向的对象和定义方式和位置没有关系
    // 只和调用的方式有关系，只有当执行时this的值才被确定

    // this的绑定规则：
    // 规则1：默认绑定
    // "use strict"  严格模式下, 独立调用的函数中的this指向的是undefined

    // 定义函数
    // 1.普通的函数被独立调用
    // function foo() {
    //   console.log("foo:", this)
    // }
    // foo()  this=>window

    // 2.函数定义在对象中, 但是独立调用
    // var obj = {
    //   name: "张三",
    //   bar: function() {
    //     console.log("bar:", this)
    //   }
    // }
    // var baz = obj.bar
    // baz()  //this=>window

    // 3.高阶函数 接收一个函数作为参数
    // function test(fn) {
    //   fn()  //obj.bar() 也是独立调用
    // }

    // test(obj.bar)  //this=>window

    // 规则2：隐式绑定
    // function foo() {
    //   console.log("foo函数:", this)
    // }

    // var obj = {
    //   bar: foo  
    // }

    // obj.bar() //this=>obj

    // 规则3：new绑定
     /*
      1.创建新的空对象
      2.将this指向这个空对象
      3.执行函数体中的代码
      4.没有显示返回非空对象时, 默认返回这个对象
    */
    function foo() {
      this.name = "张三"
      console.log("foo函数:", this)
    }

    new foo()

    // 规则4：显式绑定
    var obj = {
      name: "张三"
    }

    function foo() {
      console.log("foo函数:", this)
    }

    // 执行函数, 并且函数中的this指向obj对象
    obj.foo = foo
    obj.foo()

    // 执行函数, 并且强制this就是obj对象(参数)
    foo.call(obj)
    foo.call(123)  //123 => 包装类对象Number
    foo.call("abc") //'abc' => 包装类对象String

  </script>

</body>
</html>